{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Model Deployment to SageMaker Hosted Inference Endpoint\n",
    "This notebook deploys iso20022 pacs.008 model trained in previous notebook, [pacs008_automl_model_training.ipynb](./pacs008_automl_model_training.ipynb) to predict if a pacs.008 XML message will be successfuly processed (Success) or fail proccessing (Failure) leading to exception processing. It uses Amazon SageMaker hosting to deploy an Inference Endpoint that can be called as REST api by iso20022 pacs.008 message processors in real time and take actions, if needed, early in the payment processing flow.\n",
    "\n",
    "The diagram below shows the places in the cross-border payment message flow where a call to ML inference endpoint can be injected to get inference from the ML model. The inference result can be used to take additional actions, including corrective actions before sending the message downstream.\n",
    "\n",
    "![ML Inference Endpoint](../images/iso20022-prototype-real-time-inference.png)\n",
    "\n",
    "\n",
    "### Amazon SageMaker Inference Endpoint\n",
    "The SageMaker Inference Endpoint name after the endpoint has been created is stored in a notebook store magic variable to make it easy to test. If the Inference Endoint was created outside of this notebook then you have to obtain the inference endpoint name from SageMaker console or via aws cli.\n",
    "\n",
    "### Request Payload\n",
    "\n",
    "To test inference endpoint, you need to know the algorithm-specific format of the model artifacts that were generated by model training. For more information about output formats supported by SageMaker algorithms, see the section corresponding to the algorithm you are using in [Common Data Formats for Training](https://docs.aws.amazon.com/sagemaker/latest/dg/cdf-training.html).\n",
    "\n",
    "Supervised learning algorithms generally expect input data during inference to be in CSV or JSON format. See [Common Data Formats for Inference](https://docs.aws.amazon.com/sagemaker/latest/dg/cdf-inference.html) documentation for more details on inference request payload formats.\n",
    "\n",
    "The request payload **must** have values for features in the **same order** as they were during model training. Also note that the input payload **must** not contain target variable as that is what the model will predict based on input data.\n",
    "\n",
    "To learn about order of features examine the features used during data preparation and pre-processing stage to create training data set. For the prototype example here, the order of payload values must be the full features in the labeled raw dataset which was created from `pacs.008 XML message`.\n",
    "\n",
    "You can examine the training dataset to confirm that the order of features in it. You can also examine [00_gen_synthetic_dataset.ipynb](../synthetic-data/00_gen_synthetic_dataset.ipynb) notebook to see features in raw labeled dataset that was used in training.\n",
    "\n",
    "### Further Reading\n",
    "\n",
    "See SageMaker documentation for information on [Real-time Inference](https://docs.aws.amazon.com/sagemaker/latest/dg/realtime-endpoints.html).\n",
    "\n",
    "It is strongly recommended that you review [Best Practices for Deploying Models on SageMaker Hosting Services](https://docs.aws.amazon.com/sagemaker/latest/dg/how-it-works-hosting-related-considerations.html) for additional information."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Deploying Model "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import boto3\n",
    "import json\n",
    "import numpy as np\n",
    "import pandas as pd\n",
    "import os\n",
    "import sagemaker\n",
    "from sagemaker import get_execution_role\n",
    "from time import sleep, gmtime, strftime\n",
    "import time"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "role = get_execution_role()\n",
    "sess = sagemaker.Session()\n",
    "region = boto3.session.Session().region_name\n",
    "sm = boto3.Session().client('sagemaker')\n",
    "print (\"Executing in region {} with role {}\".format (region, role))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# retrieve stored variables from previous notebook\n",
    "%store -r"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "training_job_name"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "sm_client = boto3.client('sagemaker')\n",
    "training_job_description = sm_client.describe_training_job(TrainingJobName=training_job_name)\n",
    "\n",
    "model_data = training_job_description['ModelArtifacts']['S3ModelArtifacts']\n",
    "container_uri = training_job_description['AlgorithmSpecification']['TrainingImage']"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "sm_client.describe_training_job(TrainingJobName=training_job_name)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# model_name was restored from %store -r\n",
    "model_name"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Create a endpoint config based on the previous model\n",
    "endpoint_config = sm_client.create_endpoint_config(\n",
    "    EndpointConfigName=\"{}-config\".format(model_name),\n",
    "    ProductionVariants=[\n",
    "        {\n",
    "            'VariantName': \"{}-variant\".format(model_name),\n",
    "            'ModelName': model_name,\n",
    "            'InitialInstanceCount': 1,\n",
    "            'InstanceType': 'ml.m5.xlarge',\n",
    "            'InitialVariantWeight': 1.0,\n",
    "        }\n",
    "    ]\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "endpoint = sm_client.create_endpoint(\n",
    "            EndpointName=\"{}-endpoint\".format(model_name),\n",
    "            EndpointConfigName=\"{}-config\".format(model_name)\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from time import sleep\n",
    "\n",
    "endpoint_name = \"{}-endpoint\".format(model_name)\n",
    "\n",
    "status = sm_client.describe_endpoint(EndpointName=endpoint_name)['EndpointStatus']\n",
    "print(status)\n",
    "while status == 'Creating':    \n",
    "    sleep (60)\n",
    "    status = sm_client.describe_endpoint(EndpointName=endpoint_name)['EndpointStatus']\n",
    "    print (status)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Store Endpoint Name"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%store endpoint_name"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Test Inference Endpoint"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**NOTE**\n",
    "If inference endpoint has been created, you can test it here without executing any of the previous cells. The endpoint name is stored in the magic store.\n",
    "\n",
    "See SageMaker documentation on [testing interence endpoints](https://docs.aws.amazon.com/sagemaker/latest/dg/realtime-endpoints-test-endpoints.html)."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Restore Inference Endpoint Name"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%store -r\n",
    "print(endpoint_name)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Make Prediction by Calling Inference Endpoint"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "runtime_client = boto3.client('sagemaker-runtime')\n",
    "\n",
    "endpoint_name = 'pacs008-automl-2021-11-25-17-00-endpoint'\n",
    "# failure transaction\n",
    "failed_input = 'urn:iso:std:iso:20022:tech:xsd:head.001.001.02,ZHKQUSQQ,WELUIN4E,F8YrsBmbaTqOsPCj,pacs.008.001.08,swift.cbprplus.01,2021-11-15 03:11:41.584,urn:iso:std:iso:20022:tech:xsd:pacs.008.001.08,F8YrsBmbaTqOsPCj,2021-11-15 03:11:41.584,1.0,INDA,HydxEjO7izKjNEV4,O4MhN69232MeToG2,6df7e54c-bb3b-4535-acb7-97d6d947dee5,HIGH,PENS,USD,7952193915.0,2021-11-14 05:00:00.000,USD,7952193905.0,CRED,USD,8738055655.0,ZHKQUSQQ,HLXSUSDM,ZHKQUSQQ,WELUIN4E,XQIBINGE,Thomas Jefferson University Master Trust - Investment Grade Long Bond Account,Scott Building,19107,Philadelphia,US,KSQUUSDB,FYOAINJS,TEKION INDIA PRIVATE LIMITED,\"No 680, Fortuna 1 Building,8th Main Road, 15 Cross J P Nagar, 2nd Phas\",560078,Bangalore,IN,6723847BB,INR,TEKION INDIA PRIVATE LIMITED,EMAL,webmaster-services-peter-crazy-but-oh-so-ubber-cool-english-alphabet-loverer-abcdefghijklmnopqrstuvwxyz@please-try-to.send-me-an-email-if-you-can-possibly-begin-to-remember-this-coz.this-is-the-longest-email-address-known-to-man-but-to-be-honest.this-is-such-a-stupidly-long-sub-domain-it-could-go-on-forever.pacraig.com,PHOB,Please call the creditor as soon as funds are credited to the account.The phone number is 4234421443 or 324979347. Leave a message.,/REG/13.P1301,COMC,CRED,Reserve Bank of India,IN,Export Reporting,2021-11-14 00:00:00,IN,13.P1301,USD,7952193905.0'\n",
    "\n",
    "resp = runtime_client.invoke_endpoint(\n",
    "    EndpointName=endpoint_name,\n",
    "    Body=str.encode(failed_input),\n",
    "    ContentType='text/csv',\n",
    "    Accept='text/csv'\n",
    ")\n",
    "print(resp['Body'].read())\n",
    "\n",
    "# successful transaction\n",
    "successful_input = 'urn:iso:std:iso:20022:tech:xsd:head.001.001.02,GQTCUS19,OZRHTHO5,P89PDKtOJh0xRbNf,pacs.008.001.08,swift.cbprplus.01,2021-11-15 03:15:58.886,urn:iso:std:iso:20022:tech:xsd:pacs.008.001.08,P89PDKtOJh0xRbNf,2021-11-15 03:15:58.886,1.0,INDA,zQGr1MRgKAa25Vag,pcVAPp0dP3Z002xX,3c29c71e-4711-49a4-a664-e58b9b9d86e3,NORM,PENS,USD,9620483936.0,2021-11-14 05:00:00.000,USD,9620483868.0,CRED,USD,9279977441.0,GQTCUS19,HUMMUSAD,GQTCUS19,OZRHTHO5,DIPNTHGR,\"AB BOND FUND, INC. - AB Bond Inflation Strategy\",c/o The Corporation Trust Incorporated,21093-2252,Lutherville Timonium,US,WERGUSVB,HKTUTH7P,BARCLAYS CAPITAL (THAILAND) LIMITED,989 SAIM TOWER BUILDING FL.14,10330,PATHUM WAN,TH,6723847BB,THB,BARCLAYS CAPITAL (THAILAND) LIMITED,EMAL,webmaster-services-peter-crazy-but-oh-so-ubber-cool-english-alphabet-loverer-abcdefghijklmnopqrstuvwxyz@please-try-to.send-me-an-email-if-you-can-possibly-begin-to-remember-this-coz.this-is-the-longest-email-address-known-to-man-but-to-be-honest.this-is-such-a-stupidly-long-sub-domain-it-could-go-on-forever.pacraig.com,PHOB,Please call the creditor as soon as funds are credited to the account.The phone number is 4234421443 or 324979347. Leave a message.,,COMC,,,,,,,,,'\n",
    "\n",
    "resp = runtime_client.invoke_endpoint(\n",
    "    EndpointName=endpoint_name,\n",
    "    Body=str.encode(successful_input),\n",
    "    ContentType='text/csv',\n",
    "    Accept='text/csv'\n",
    ")\n",
    "print(resp['Body'].read())\n",
    "\n",
    "# successful transaction\n",
    "successful_input = 'urn:iso:std:iso:20022:tech:xsd:head.001.001.02,TVFVGBQO,HKTUTH7P,lXZYU4dlh7BgtV9Y,pacs.008.001.08,swift.cbprplus.01,2021-11-15 03:15:38.791,urn:iso:std:iso:20022:tech:xsd:pacs.008.001.08,lXZYU4dlh7BgtV9Y,2021-11-15 03:15:38.791,1.0,INDA,H04QwlcnIvOnDVWk,geZVvAzWiDQnPqip,9687e8e7-73d3-4594-a889-bbbc9e58643b,HIGH,VATX,GBP,6490589583.0,2021-11-14 05:00:00.000,GBP,6490589528.0,CRED,GBP,6887326681.0,TVFVGBQO,WSTQGBGD,TVFVGBQO,HKTUTH7P,WPVLTHYK,POLLARD FAMILY PENSION SCHEME,C/O DCD TRUSTEES LIMITED,EC2A 4PJ,LONDON,GB,ZXLCGBYY,ITZWTHXB,1YM2,\"7th-8th Floor, SCB Park Plaza 1\",10900,Bangkok,TH,6723847BB,THB,1YM2,EMAL,webmaster-services-peter-crazy-but-oh-so-ubber-cool-english-alphabet-loverer-abcdefghijklmnopqrstuvwxyz@please-try-to.send-me-an-email-if-you-can-possibly-begin-to-remember-this-coz.this-is-the-longest-email-address-known-to-man-but-to-be-honest.this-is-such-a-stupidly-long-sub-domain-it-could-go-on-forever.pacraig.com,PHOB,Please call the creditor as soon as funds are credited to the account.The phone number is 4234421443 or 324979347. Leave a message.,,COMC,,,,,,,,,'\n",
    "\n",
    "resp = runtime_client.invoke_endpoint(\n",
    "    EndpointName=endpoint_name,\n",
    "    Body=str.encode(successful_input),\n",
    "    ContentType='text/csv',\n",
    "    Accept='text/csv'\n",
    ")\n",
    "print(resp['Body'].read())\n",
    "\n",
    "# another example with failure prediction\n",
    "failed_input = \"urn:iso:std:iso:20022:tech:xsd:head.001.001.02,VGBBCA66,LXFTGBGS,c49gS37XG5Wtc9Ca,pacs.008.001.08,swift.cbprplus.01,2021-11-15 03:41:23.243,urn:iso:std:iso:20022:tech:xsd:pacs.008.001.08,c49gS37XG5Wtc9Ca,2021-11-15 03:41:23.243,1.0,INDA,aTB6f0l7qCqNYqQh,mkgE0j7JcJCSGNMq,561aee1b-ee4f-4e9f-8315-07a7038f0fa4,NORM,ICCP,CAD,3053772770.0,2021-11-14 05:00:00.000,CAD,3053772726.0,SHAR,,,,AYZLCA7F,VGBBCA66,LXFTGBGS,ZJKCGBZ9,8532630 CANADA INC,1801-200 AVENUE DES SOMMETS,H3E 2B4,VERDUN,CA,JCBACAIB,MRNSGBPD,IBM UNITED KINGDOM LIMITED,P.O. BOX 41,PO6 3AU,PORTSMOUTH,GB,84349274229,GBP,IBM UNITED KINGDOM LIMITED,EMAL,webmaster-services-peter-crazy-but-oh-so-ubber-cool-english-alphabet-loverer-abcdefghijklmnopqrstuvwxyz@please-try-to.send-me-an-email-if-you-can-possibly-begin-to-remember-this-coz.this-is-the-longest-email-address-known-to-man-but-to-be-honest.this-is-such-a-stupidly-long-sub-domain-it-could-go-on-forever.pacraig.com,PHOB,Please call the creditor as soon as funds are credited to the account.The phone number is 4234421443 or 324979347. Leave a message.,/SVC/It is to be delivered in one business day. Two day penalty 7bp;greater than two days penalty add 8bp per day.,COMC,,,,,,,,,\"\n",
    "\n",
    "resp = runtime_client.invoke_endpoint(\n",
    "    EndpointName=endpoint_name,\n",
    "    Body=str.encode(failed_input),\n",
    "    ContentType='text/csv',\n",
    "    Accept='text/csv'\n",
    ")\n",
    "print(resp['Body'].read())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "instance_type": "ml.g4dn.xlarge",
  "kernelspec": {
   "display_name": "Python 3 (Data Science)",
   "language": "python",
   "name": "python3__SAGEMAKER_INTERNAL__arn:aws:sagemaker:us-east-1:081325390199:image/datascience-1.0"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.10"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
